#import "Printer.h"
#import "Calculette.h"

@implementation Printer

- text
{
  return text;
}
  
- window
{
  return window;
}

- (char *)file
{
  return file;
}

- appendToText:(const char *)aText
{
  [ text replaceSel:aText ];

  [ text scrollSelToVisible ];
  [ text display ];

  [ window setDocEdited:YES ];

  return self ;
}

- setFile:(const char *)aFile
{
  if ( file == aFile )		/* revert to saved */
    return self;

  if ( file )
    free( file );

  file = strcpy( (char *)malloc( strlen( aFile ) + 1 ), aFile );

  [ window setTitle:rindex( file, '/' ) ? rindex( file, '/' ) + 1 : file ];
 
  return self;
}

- load:(const char *)aFile
{
  NXStream *theStream = NXMapFile( aFile, NX_READONLY );
  id ret = self;

  if ( theStream ) {
    NX_DURING
    [ text readRichText:theStream ];

    NX_HANDLER
    switch ( NXLocalHandler.code ) {
    case NX_illegalWrite:
      NXRunAlertPanel( 0, "Illegal write on stream", 0, 0, 0 );
      ret = nil;
      break;
    case NX_illegalRead:
      NXRunAlertPanel( 0, "Illegal read on stream", 0, 0, 0 );
      ret = nil;
      break;
    case NX_illegalSeek:
      NXRunAlertPanel( 0, "Illegal seek on stream", 0, 0, 0 );
      ret = nil;
      break;
    case NX_illegalStream:
      NXRunAlertPanel( 0, "Invalid stream", 0, 0, 0 );
      ret = nil;
      break;
    case NX_streamVMError:
      NXRunAlertPanel( 0, "VM error on stream", 0, 0, 0 );
      ret = nil;
      break;
    }
    NX_ENDHANDLER

    NXCloseMemory( theStream, NX_FREEBUFFER );

    if ( ret ) {
      [ self setFile:aFile ];
      [ window setDocEdited:NO ];
      [ text setSel:0 :0 ];
    }

    return ret;
  }
  NXRunAlertPanel( 0, "The file %s cannot be opened. File system error: %s",
		  0, 0, 0, file, strerror( errno ));
  return nil;
}

- saveAs:sender
{
  SavePanel *savePanel = [ SavePanel new ];

  [ savePanel setRequiredFileType:"calculette" ];
  if ( [ savePanel runModal ] != NX_OKTAG )
    return nil;

  [ self setFile:[ savePanel filename ]];

  return [ self save:sender ];
}

- save:sender
{
  int fd;
  NXStream *theStream;

  if ( !file )
    return [ self saveAs:sender ];

  if ( access( file, F_OK ) == 0 && access( file, W_OK ) != 0 )
    if( NXRunAlertPanel( 0, "The file %s is write protected. Do you want to overwrite it?",
			"Replace", "Cancel", 0, file ) != NX_ALERTDEFAULT )
      return nil;

  if ( (fd = open( file, O_WRONLY|O_CREAT|O_TRUNC, 0666 )) < 0 ) {
    NXRunAlertPanel( 0, "The file %s cannot be saved. File system error: %s",
		    0, 0, 0, file, strerror( errno ));
    return nil;
  }

  theStream = NXOpenFile( fd, NX_WRITEONLY );

  [ text writeRichText:theStream ];

  NXClose( theStream );
  close( fd );
  
  [ window setDocEdited:NO ];

  return self;
}

- revert:sender
{
  if ( !file )
    return nil;

  if ( [ window isDocEdited ] )
    if( NXRunAlertPanel( 0, "Do you want to discard changes to %s?",
			"Revert", "Cancel", 0, file ) != NX_ALERTDEFAULT )
      return nil;

  return [ self load:file ];
}

- print:sender
{
  [ text printPSCode:nil ];
  
  return self;
}

@end

@implementation Printer( WindowDelegate )

- windowDidBecomeKey:sender
{
  [[ NXApp delegate ] changePrinter:self ];

  return self;
}

- windowWillClose:sender
{
  if ( [ sender isDocEdited ] ) {
    const char *fname = file ? file : [ sender title ];

    if ( rindex( fname, '/' ))
      fname = rindex( fname, '/' ) + 1;
      
      switch ( NXRunAlertPanel( "Close", "Save changes to %s?", "Save", "Don't Save", "Cancel", fname )) {
      case NX_ALERTDEFAULT:
        if ( ![ self save:nil ] )
	  return nil;
	break;
      case NX_ALERTOTHER:
        return nil;
      default:
	break;
      }
  }

  [ sender setDelegate:nil ];

  [[ NXApp delegate ] removePrinter:self ];

  [ self free ];

  return self;
}

- windowWillMiniaturize:sender toMiniwindow:miniwindow
{
  [ sender setMiniwindowIcon:"Miniprinter" ];

  return self;
}

@end

@implementation Printer( TextDelegate )

- textDidGetKeys:sender isEmpty:(BOOL)flag
{
  [ window setDocEdited:YES ];

  return self;
}

- textWillConvert:sender fromFont:from toFont:to
{
  [ window setDocEdited:YES ];

  return to;
}

@end
